package com.hezuti.common.dao;

import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Criteria;
import org.hibernate.EntityMode;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Example;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Property;
import org.hibernate.criterion.Restrictions;
import org.hibernate.impl.SessionFactoryImpl;
import org.hibernate.metadata.ClassMetadata;
import org.omg.CORBA.portable.ApplicationException;
import org.springframework.jdbc.object.SqlQuery;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;

import com.hezuti.common.page.PageInfo;


/**
 * 
 * @author xiaoyu.dou
 *
 */
public class BaseHibernateDao extends BaseHibernateDaoSupport implements Pageable, Countable {
	Log sqlLog = LogFactory.getLog(getClass());

	@SuppressWarnings("unchecked")
	public Query createQuery(String hql, List values) {
		Assert.hasText(hql);
		Query query = getSession().createQuery(hql);
		int i = 0;
		for (Object param : values) {
			query.setParameter(i++, param);
		}
		return query;
	}

	/**
	 * 查找一个对象,没有找到则抛出异常
	 * 
	 * @param <T>
	 * @param entityClass
	 * @param id
	 * @return
	 * @throws ApplicationException
	 */
	@SuppressWarnings("unchecked")
	public final <T> T load(Class<T> entityClass, Serializable id) {
		Assert.notNull(id);
		return (T) getHibernateTemplate().load(entityClass, id);
	}

	/**
	 * 得到一个对象,没有返回null
	 * 
	 * @param <T>
	 * @param entityClass
	 * @param id
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public final <T> T get(Class<T> entityClass, Serializable id) {
		Assert.notNull(id);
		return (T) getHibernateTemplate().get(entityClass, id);
	}

	/**
	 * 根据hql得到一个对象,没有返回null;
	 * 
	 * @param <T>
	 * @param hql
	 * @param params
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public final <T> T get(String hql, List params) {
		Assert.hasText(hql);
		Object[] array = CollectionUtils.isEmpty(params) ? new Object[] {} : params.toArray();
		Iterator<T> iterator = getHibernateTemplate().iterate(hql, array);
		if (iterator.hasNext()) {
			return (T) iterator.next();
		} else {
			return null;
		}
	}

	/**
	 * 根据hql语句得到对象列表
	 * 
	 * @param <T>
	 * @param hql
	 * @param params
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public final <T> List<T> findList(final String hql, final List params) {
		Assert.hasText(hql);
		Object[] array = CollectionUtils.isEmpty(params) ? new Object[] {} : params.toArray();
		List<T> list = (List<T>) getHibernateTemplate().find(hql, array);
		return list;
	}

	/**
	 * 根据Querable查找对象列表
	 * 
	 * @param <T>
	 * @param hql
	 * @param params
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public final <T> List<T> findList(final Queryable qAble) {
		Assert.isInstanceOf(SqlQuery.class, qAble);
		Query query = createQuery(qAble.getQueryStr(), qAble.getParams());
		List<T> list = query.list();
		return list;
	}

	/**
	 * 查询指定数量的对象
	 */
	@SuppressWarnings("unchecked")
	public final <T> List<T> findList(final String hql, List params, final int maxCnt) {
		Query query = createQuery(hql, params);
		List<T> result = query.setFirstResult(0).setMaxResults(maxCnt).list();
		return result;
	}

	/**
	 * 查询指定数量的对象
	 */
	@SuppressWarnings("unchecked")
	public final <T> List<T> findList(final Queryable qAble, final int maxCnt) {
		Assert.isInstanceOf(SqlQuery.class, qAble);
		Query query = createQuery(qAble.getQueryStr(), qAble.getParams());
		List<T> result = query.setFirstResult(0).setMaxResults(maxCnt).list();
		return result;
	}

	/**
	 * 查询指定数量的对象
	 */
	@SuppressWarnings("unchecked")
	public final <T> List<T> findList(final String hql, List params, final int minCnt, final int maxCnt) {
		Query query = createQuery(hql, params);
		List<T> result = query.setFirstResult(minCnt).setMaxResults(maxCnt).list();
		return result;
	}

	/**
	 * 根据传入的对象id列表,返回对应的对象列表
	 * 
	 * @param <T>
	 * @param entityClass
	 * @param ids
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public final <T> List<T> findListByIds(final Class<T> entityClass, final List<Serializable> ids) {
		Assert.notEmpty(ids);

		return getHibernateTemplate().executeFind(new HibernateCallback() {
			public Object doInHibernate(Session session) throws HibernateException, SQLException {
				Criteria c = session.createCriteria(entityClass);
				String idName = getSessionFactory().getClassMetadata(entityClass).getIdentifierPropertyName();
				c.add(Restrictions.in(idName, ids.toArray()));
				return c.list();
			}
		});
	}

	/**
	 * 保存或更新一个对象
	 * 
	 * @param <T>
	 * @param o
	 * @return
	 */
	public final <T> T save(T o) {
		getHibernateTemplate().saveOrUpdate(o);
		getHibernateTemplate().flush();
		return o;
	}

	public final <T> void saveAll(Collection<T> collection) {
		Assert.notEmpty(collection);
		getHibernateTemplate().saveOrUpdateAll(collection);
	}

	/**
	 * 根据id删除一个对象
	 * 
	 * @param <T>
	 * @param entityClass
	 * @param id
	 */
	public final <T> void delete(Class<T> entityClass, Serializable id) {
		Assert.notNull(id);
		delete(get(entityClass, id));
	}

	/**
	 * 删除一个对象
	 * 
	 * @param o
	 */
	public final void delete(Object o) {
		Assert.notNull(o);
		HibernateTemplate template = getHibernateTemplate();
		template.delete(o);
		template.flush();
		template.evict(o);
	}

	/**
	 * 根据指定的对象id列表,删除对应的对象
	 * 
	 * @param <T>
	 * @param entityClass
	 * @param ids
	 */
	public final <T> void deleteAll(Class<T> entityClass, List<Serializable> ids) {
		if (CollectionUtils.isEmpty(ids))
			return;
		deleteAll(findListByIds(entityClass, ids));
	}

	/**
	 * 删除指定的对象列表
	 * 
	 * @param <T>
	 * @param entities
	 */
	public final <T> void deleteAll(Collection<T> entities) {
		if (CollectionUtils.isEmpty(entities))
			return;
		getHibernateTemplate().deleteAll(entities);
		getHibernateTemplate().flush();
	}

	/**
	 * 清除某个对象cache
	 * 
	 * @param entityClass
	 * @param id
	 */
	public final <T> void evict(final Class<T> entityClass, final Serializable id) {
		getHibernateTemplate().getSessionFactory().evict(entityClass, id);
	}

	/**
	 * 清楚list的cache
	 * 
	 * @param <T>
	 * @param entityClass
	 * @param idList
	 */
	public final <T> void evicts(final Class<T> entityClass, final List<Serializable> idList) {
		if (CollectionUtils.isEmpty(idList))
			return;
		SessionFactory factory = getHibernateTemplate().getSessionFactory();
		for (Serializable id : idList)
			factory.evict(entityClass, id);
	}

	/**
	 * 分页查询
	 */
	@SuppressWarnings("unchecked")
	public <T> List<T> pagedQuery(final PageInfo page, final Class<T> entityClass, final Queryable q) {
		int pageNo = (int) page.getCurrentPageNo();
		int pageSize = page.getPageSize();
		Assert.isTrue(pageNo > 0, "pageNo should start from 1");
		Assert.isTrue(pageSize > 0, "pageNo should start from 1");
		// Assert.isInstanceOf(SqlQuery.class, q);

		int count = count(q);
		page.setTotalCount(count);

		if (count > 0) {
			int start = (pageNo - 1) * pageSize;
			Query query = createQuery(q.getQueryStr(), q.getParams());
			List<T> result = query.setFirstResult(start).setMaxResults(pageSize).list();
			return result;
		} else {
			return null;
		}
	}

	/**
	 * Hibernate 调Sql分页查询，可返回多个对象映射
	 * 
	 * @param q
	 *            应为HibernateSqlQuery
	 */
	@SuppressWarnings("unchecked")
	public List pagedSqlQuery(PageInfo page, Queryable q) {
		int pageNo = (int) page.getCurrentPageNo();
		int pageSize = page.getPageSize();
		Assert.isTrue(pageNo > 0, "pageNo should start from 1");
		Assert.isTrue(pageSize > 0, "pageNo should start from 1");
		Assert.isInstanceOf(HibernateSqlQuery.class, q);

		HibernateSqlQuery config = (HibernateSqlQuery) q;
		int count = sqlCount(config);
		page.setTotalCount(count);

		if (count > 0) {
			StringBuffer sql = new StringBuffer();
			if (pageNo == PageInfo.FIRST_PAGE_NO) { // 查询第一页
				sql.append("select top ").append(pageSize).append(" * from ( ");
				sql.append("       ").append(config.getSqlWithoutOrderby()).append(" ");
				sql.append(") _a ");
				sql.append(config.getOrderby(true));
			} else if (count <= pageNo * pageSize) { // 查询最后一页
				int size = count - (pageNo - 1) * pageSize;
				if (size < 1)
					return null;
				sql.append("select * from (");
				sql.append("       select top ").append(size).append(" * from ( ");
				sql.append("              ").append(config.getSqlWithoutOrderby()).append(" ");
				sql.append("       ) _a ");
				sql.append("       ").append(config.getReverseOrderby(true));
				sql.append(") _b ");
				sql.append(config.getOrderby(true));
			} else { // 查询中间的页
				sql.append("select *").append(" ");
				sql.append("from (").append(" ");
				sql.append("     select top ").append(pageSize).append(" * from (").append(" ");
				sql.append("            select top ").append(pageNo * pageSize).append(" * from (").append(" ");
				sql.append("                   ").append(config.getSqlWithoutOrderby());
				sql.append("            ) _c").append(" ");
				sql.append("            ").append(config.getOrderby(true)).append(" ");
				sql.append("     ) _a").append(" ");
				sql.append("     ").append(config.getReverseOrderby(true)).append(" ");
				sql.append(") _b").append(" ");
				sql.append(config.getOrderby(true)).append(" ");
			}

			SQLQuery sq = createSqlQuery(sql.toString());
			// 添加实体映射
			for (int i = 0; i < config.getEntitySize(); i++) {
				sq.addEntity(config.getEntityName(i), config.getEntityClass(i));
			}

			return sq.list();
		} else
			return null;
	}

	/**
	 * count
	 */
	public int count(Queryable q) {
		// Assert.isInstanceOf(SqlQuery.class, q);
		return count(q.getCountStr(), q.getParams());
	}

	/**
	 * hibernate下sql查询时用的count
	 */
	public int sqlCount(Queryable q) {
		return ((Integer) createSqlQuery(q.getCountStr()).uniqueResult()).intValue();
	}

	/**
	 * 根据sql,返回count
	 */
	@SuppressWarnings("unchecked")
	public int count(String sql, List<Object> params) {
		List result = getHibernateTemplate().find(sql, CollectionUtils.isEmpty(params) ? null : params.toArray());
		return ((Long) result.get(0)).intValue();
	}

	/**
	 * 根据sql,返回count
	 */
	@SuppressWarnings("unchecked")
	public int count(String sql, Object[] params) {
		List result = getHibernateTemplate().find(sql, params);
		return ((Long) result.get(0)).intValue();
	}

	/**
	 * 根据sql,返回count
	 */
	@SuppressWarnings("unchecked")
	public int count(String sql) {
		List result = getHibernateTemplate().find(sql);
		return ((Long) result.get(0)).intValue();
	}

	/**
	 * 创建Criteria对象.
	 * 
	 * @param criterions
	 *            可变的Restrictions条件列表,见{@link #createQuery(String,Object...)}
	 */
	public <T> Criteria createCriteria(Class<T> entityClass, Criterion... criterions) {
		Criteria criteria = getSession().createCriteria(entityClass);
		for (Criterion c : criterions) {
			criteria.add(c);
		}
		// 使用HibernateSessionFactory中的Use_queryCache配置来设置本参数
		criteria.setCacheable(((SessionFactoryImpl) getSessionFactory()).getSettings().isQueryCacheEnabled());
		// if(entityClass.getAnnotation(Cache.class)!=null)
		// criteria.setCacheable(true);
		return criteria;
	}

	/**
	 * 创建Criteria对象，带排序字段与升降序字段.
	 * 
	 * @see #createCriteria(Class,Criterion[])
	 */
	public <T> Criteria createCriteria(Class<T> entityClass, String orderBy, boolean isAsc, Criterion... criterions) {
		Assert.hasText(orderBy);

		Criteria criteria = createCriteria(entityClass, criterions);

		if (isAsc)
			criteria.addOrder(Order.asc(orderBy));
		else
			criteria.addOrder(Order.desc(orderBy));

		return criteria;
	}

	/**
	 * 创建Query对象.
	 * 对于需要first,max,fetchsize,cache,cacheRegion等诸多设置的函数,可以在返回Query后自行设置.
	 * 留意可以连续设置,如下：
	 * 
	 * <pre>
	 * dao.getQuery(hql).setMaxResult(100).setCacheable(true).list();
	 * </pre>
	 * 
	 * 调用方式如下：
	 * 
	 * <pre>
	 *               dao.createQuery(hql)
	 *               dao.createQuery(hql,arg0);
	 *               dao.createQuery(hql,arg0,arg1);
	 *               dao.createQuery(hql,new Object[arg0,arg1,arg2])
	 * </pre>
	 * 
	 * @param values
	 *            可变参数.
	 */
	public Query createQuery(String hql, Object... values) {
		Assert.hasText(hql);
		Query query = getSession().createQuery(hql);
		for (int i = 0; values != null && i < values.length; i++) {
			query.setParameter(i, values[i]);
		}
		return query;
	}

	/**
	 * 根据hql查询,直接使用HibernateTemplate的find函数.
	 * 
	 * @param values
	 *            可变参数,见{@link #createQuery(String,Object...)}
	 */
	@SuppressWarnings("unchecked")
	public List find(String hql, Object... values) {
		Assert.hasText(hql);
		return getHibernateTemplate().find(hql, values);
	}

	/**
	 * 根据hql查询,直接使用HibernateTemplate的find函数.
	 */
	@SuppressWarnings("unchecked")
	public List find(String hql) {
		Assert.hasText(hql);
		return getHibernateTemplate().find(hql);
	}

	/**
	 * 根据属性名和属性值查询对象.
	 * 
	 * @return 符合条件的对象列表
	 */
	@SuppressWarnings("unchecked")
	public <T> List<T> findBy(Class<T> entityClass, String propertyName, Object value) {
		Assert.hasText(propertyName);
		Criteria criteria = createCriteria(entityClass, Restrictions.eq(propertyName, value));
		criteria.setCacheable(((SessionFactoryImpl) getSessionFactory()).getSettings().isQueryCacheEnabled());
		// if(entityClass.getAnnotation(Cache.class)!=null)
		// criteria.setCacheable(true);
		return criteria.list();
	}

	/**
	 * 根据属性名和属性值模糊查找对象
	 * 
	 * @param entityClass
	 * @param propertyName
	 * @param value
	 *            字符型，如："%广告%"
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public <T> List<T> findByLike(Class<T> entityClass, String propertyName, String value) {
		Assert.hasText(propertyName);
		return createCriteria(entityClass, Restrictions.like(propertyName, value)).list();
	}

	/**
	 * 根据属性名和属性值查询对象,带排序参数.
	 */
	@SuppressWarnings("unchecked")
	public <T> List<T> findBy(Class<T> entityClass, String propertyName, Object value, String orderBy, boolean isAsc) {
		Assert.hasText(propertyName);
		Assert.hasText(orderBy);
		return createCriteria(entityClass, orderBy, isAsc, Restrictions.eq(propertyName, value)).list();
	}

	/**
	 * 根据事例查找持久对象
	 * 
	 * @param entityClass
	 * @param instance
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public <T> List<T> findByExample(final Class<T> entityClass, final Object instance, final String orderBy, final Boolean isAsc, final Boolean islike,
			final Criterion... criterions) {
		sqlLog.debug("finding " + entityClass.toString() + " instance by example");
		HibernateTemplate hibernateTemplate = getHibernateTemplate();
		return hibernateTemplate.executeFind(new HibernateCallback() {

			public Object doInHibernate(Session session) throws HibernateException, SQLException {
				try {
					Criteria criteria = session.createCriteria(entityClass);
					Example e = Example.create(instance);
					if (islike)
						e.enableLike(MatchMode.ANYWHERE);
					criteria.add(e);
					String idName = getSessionFactory().getClassMetadata(entityClass).getIdentifierPropertyName();
					Serializable idValue = getSessionFactory().getClassMetadata(entityClass).getIdentifier(instance, EntityMode.POJO);

					if (idValue != null) {
						criteria.add(Property.forName(idName).eq(idValue));
					}
					// 添加自定义排序
					if (StringUtils.isNotBlank(orderBy))
						criteria.addOrder(isAsc ? Order.asc(orderBy) : Order.desc(orderBy));
					// 添加自定义条件
					if (criterions != null) {
						for (Criterion c : criterions) {
							if (c != null)
								criteria.add(c);
						}

					}
					List results = criteria.list();
					sqlLog.debug("find by example successful, result size: " + results.size());
					return results;
				} catch (RuntimeException re) {
					sqlLog.error("find by example failed", re);
					throw re;
				}
			}

		});
	}

	/**
	 * 根据事例查找持久对象
	 * 
	 * @param entityClass
	 * @param instance
	 * @return
	 */
	public <T> List<T> findByExample(Class<T> entityClass, Object instance, Boolean islike, Criterion... criterions) {
		return findByExample(entityClass, instance, null, null, islike, criterions);
	}

	/**
	 * 根据事例查找持久对象
	 * 
	 * @param entityClass
	 * @param instance
	 * @return
	 */
	public <T> List<T> findByExample(Class<T> entityClass, Object instance, Boolean islike) {
		// return findByExample(entityClass, instance, islike, null);
		return findByExample(entityClass, instance, islike, new Criterion[] {});
	}

	/**
	 * 根据属性名和属性值查询唯一对象.
	 * 
	 * @return 符合条件的唯一对象 or null if not found.
	 */
	public <T> T findUniqueBy(Class<T> entityClass, String propertyName, Object value) {
		Assert.hasText(propertyName);
		return findUniqueBy(entityClass, createCriteria(entityClass, Restrictions.eq(propertyName, value)));
	}

	/**
	 * 根据criteria查询唯一对象.
	 * 
	 * @return 符合条件的唯一对象 or null if not found.
	 */
	@SuppressWarnings("unchecked")
	public <T> T findUniqueBy(Class<T> entityClass, Criteria criteria) {
		Assert.notNull(criteria);
		return (T) criteria.uniqueResult();
	}

	/**
	 * 根据Criteria查询出记录列表
	 * 
	 * @param <T>
	 * @param entityClass
	 * @param criteria
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public <T> List<T> findBy(Class<T> entityClass, Criteria criteria) {
		Assert.notNull(criteria);
		return (List<T>) criteria.list();
	}

	/**
	 * 获得全部数据
	 */
	@SuppressWarnings("unchecked")
	public <T> List<T> getAll(Class<T> entityClass) {
		sqlLog.debug("FindAll " + entityClass.toString() + " instance");
		try {
			return getHibernateTemplate().loadAll(entityClass);
		} catch (RuntimeException re) {
			sqlLog.error("findAll failed", re);
			throw re;
		}
	}

	/**
	 * 获取全部对象,带排序字段与升降序参数.
	 */
	@SuppressWarnings("unchecked")
	public <T> List<T> getAll(Class<T> entityClass, String orderBy, boolean isAsc) {
		Assert.hasText(orderBy);
		if (isAsc)
			return getHibernateTemplate().findByCriteria(DetachedCriteria.forClass(entityClass).addOrder(Order.asc(orderBy)));
		else
			return getHibernateTemplate().findByCriteria(DetachedCriteria.forClass(entityClass).addOrder(Order.desc(orderBy)));
	}

	/**
	 * 取得对象的主键值,辅助函数.
	 */
	@SuppressWarnings("unchecked")
	public Serializable getId(Class entityClass, Object entity) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
		Assert.notNull(entity);
		Assert.notNull(entityClass);
		return (Serializable) PropertyUtils.getProperty(entity, getIdName(entityClass));
	}

	/**
	 * 取得对象的主键名,辅助函数.
	 */
	@SuppressWarnings("unchecked")
	public String getIdName(Class clazz) {
		Assert.notNull(clazz);
		ClassMetadata meta = getSessionFactory().getClassMetadata(clazz);
		Assert.notNull(meta, "Class " + clazz + " not define in hibernate session factory.");
		String idName = meta.getIdentifierPropertyName();
		Assert.hasText(idName, clazz.getSimpleName() + " has no identifier property define.");
		return idName;
	}

	/**
	 * 判断对象某些属性的值在数据库中是否唯一.
	 * 
	 * @param uniquePropertyNames
	 *            在POJO里不能重复的属性列表,以逗号分割 如"name,loginid,password"
	 */
	@SuppressWarnings("unchecked")
	public boolean isUnique(Class entityClass, Object entity, String uniquePropertyNames) {
		Assert.hasText(uniquePropertyNames);
		Criteria criteria = createCriteria(entityClass).setProjection(Projections.rowCount());
		String[] nameList = uniquePropertyNames.split(",");
		try {
			// 循环加入唯一列
			for (String name : nameList) {
				criteria.add(Restrictions.eq(name, PropertyUtils.getProperty(entity, name)));
			}

			// 以下代码为了如果是update的情况,排除entity自身.
			String idName = getIdName(entityClass);

			// 取得entity的主键值
			Serializable id = getId(entityClass, entity);

			// 如果id!=null,说明对象已存在,该操作为update,加入排除自身的判断
			if (id != null)
				criteria.add(Restrictions.not(Restrictions.eq(idName, id)));
		} catch (Exception e) {
			ReflectionUtils.handleReflectionException(e);
		}
		return (Integer) criteria.uniqueResult() == 0;
	}

	/**
	 * 合并对象，与数据库中已存在对象合并数据字段，重新关联托管对象 随时合并你的的改动而不考虑session的状态
	 * 
	 * @param detachedInstance
	 * @param skipField
	 *            跳过的字段，不合并的字段，多字段逗号分开
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public <T> T merge(Class<T> entityClass, T detachedInstance, String skipField) {
		T result = detachedInstance;
		sqlLog.debug("merging " + detachedInstance.getClass().toString() + " instance");
		try {
			Serializable id = getId(entityClass, detachedInstance);
			if (id == null)
				throw new RuntimeException("merge Error！entity ID is Null！");
			T t = get(entityClass, id);
			if (t != null)
				result = t;
			ClassMetadata meta = getSessionFactory().getClassMetadata(entityClass);
			String[] propertyNameList = meta.getPropertyNames();
			List sf = new ArrayList();
			if (skipField != null) {
				sf = Arrays.asList(skipField.split(","));
			}
			for (String propName : propertyNameList) {
				if (t == null) {
					if (sf.contains(propName))
						meta.setPropertyValue(result, propName, null, EntityMode.POJO);
				} else {
					if (meta.getPropertyValue(detachedInstance, propName, EntityMode.POJO) != null && !sf.contains(propName))
						meta.setPropertyValue(result, propName, meta.getPropertyValue(detachedInstance, propName, EntityMode.POJO), EntityMode.POJO);
				}
			}

			sqlLog.debug("merge successful");
		} catch (RuntimeException re) {
			sqlLog.error("merge failed", re);
			throw re;
		} catch (Exception e) {
			ReflectionUtils.handleReflectionException(e);
		}
		return result;
	}

	/**
	 * 合并对象，与数据库中已存在对象合并数据字段，重新关联托管对象 随时合并你的的改动而不考虑session的状态
	 * 
	 * @param detachedInstance
	 * @param skipField
	 *            跳过的字段，不合并的字段，多字段逗号分开
	 * @return
	 */
	public <T> T merge(Class<T> entityClass, T detachedInstance) {
		return merge(entityClass, detachedInstance, null);
	}

	public SQLQuery createSqlQuery(String sql) {
		return getSession().createSQLQuery(sql);
	}

	public void flush() {
		getHibernateTemplate().flush();
	}

	public void clear() {
		getHibernateTemplate().clear();
	}

	public void flushAndClear() {
		flush();
		clear();
	}
}
